package com.zj.statement;

import com.zj.exception.ZJBatisException;
import com.zj.executor.*;
import com.zj.mapping.BoundSql;
import com.zj.mapping.MappedStatement;
import com.zj.utils.Configuration;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

public abstract class BaseStatementHandler implements StatementHandler{

    protected final Configuration configuration;

//    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final ResultSetHandler resultSetHandler;
    protected final ParameterHandler parameterHandler;

    protected final Executor executor;
    protected final MappedStatement mappedStatement;
    protected BoundSql boundSql;

    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;
//        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
        if (boundSql == null) { // issue #435, get the key before calculating the statement
            boundSql = mappedStatement.getBoundSql(parameterObject);
        }
        this.boundSql = boundSql;

        this.parameterHandler =  new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
        this.resultSetHandler = new FastResultSetHandler(executor, mappedStatement,parameterHandler, boundSql);
    }

    public Statement prepare(Connection connection) throws SQLException {
        Statement statement = null;
        try {
            statement = instantiateStatement(connection);

            return statement;
        } catch (Exception e) {
            closeStatement(statement);
            throw new ZJBatisException("Error preparing statement.  Cause: " + e);
        }
    }

    protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

    @Override
    public void parameterize(Statement statement) throws SQLException {
        parameterHandler.setParameters((PreparedStatement) statement);
    }

    @Override
    public void batch(Statement statement) throws SQLException {

    }

    @Override
    public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute();
        int rows = ps.getUpdateCount();
        return rows;
    }

    public <E> List<E> query(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement) statement;
        ps.execute();
        return resultSetHandler.<E> handleResultSets(ps);
    }

    protected void closeStatement(Statement statement) {
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            //ignore
        }
    }

}
